import java.util.ArrayList;

public class PopulationMember
{
	ArrayList<Player> playerDNA;
	private double _cache_fitness; 
	private int    destatic;

	public PopulationMember(ArrayList<Player> dna){
		this.playerDNA      = dna;
		this.destatic       = 4; // "count"
		this._cache_fitness = -1;
	}

	public ArrayList<Player> getPlayerDNA() {
		return playerDNA;
	}

	public boolean hasPlayer( Player p ) {
		for ( int i = 0; i < this.playerDNA.size(); ++i )
			if ( this.playerDNA.get(i).hasSameID(p))
				return true;
		return false;
	}

	@SuppressWarnings("unchecked")
	public PopulationMember mate(PopulationMember daddy){
		ArrayList<Player> daddyDNA = (ArrayList<Player>) daddy.getPlayerDNA().clone();
		ArrayList<Player> babyDNA  = new ArrayList<Player>();
		PopulationMember baby = null;

		int n = (int)(Math.random() * (this.playerDNA.size() - 3));
		for ( int i = 0; i < n; ++i )
			babyDNA.add(this.playerDNA.get(i));

		// System.out.println("Swaped off " + n);

		while ( daddyDNA.size() > 0 ) {

			// System.out.println("Daddy DNA is " + daddyDNA.size());

			int gene = (int)(Math.random() * daddyDNA.size());

			// System.out.println("Processing " + gene );

			Player p = daddyDNA.get(gene);
			daddyDNA.remove(gene);

			boolean found = false;

			for ( int i = 0; i < babyDNA.size(); ++i ) {
				if ( babyDNA.get(i).hasSameID(p) ) {
					found = true;
					// System.out.println("Found");
				}
			}

			if ( ! found ) {
				babyDNA.add(p);
				// System.out.println("Added " + p.getID() );
			}// else {
			//	System.out.println("Not Found");
			// }

			baby = new PopulationMember(babyDNA);
		}
		/*// Checks that the mating is working properly.
		System.out.println("This.playerDNA: " + this.toString());
		System.out.println("daddyDNA:       " + daddy.toString());
		System.out.println("babyDNA:        " + baby.toString());
		 */
		return baby;

	}
	public String toString() {
		String ret = "";
		ret += "[ ";
		for ( int i = 0; i < this.playerDNA.size(); ++i ) {
			try {
				ret += this.playerDNA.get(i).getStat("name").value + ", ";
			} catch ( WTFException e ) {
				ret += this.playerDNA.get(i).getID();
			}
		}
		ret += " ]";
		return ret;
	}

	public double evaluate(){		
		if ( this._cache_fitness >= 0 ) {
			System.out.println("Cache hit");
			return this._cache_fitness; // if we have a cache, use it.
		}

		System.out.println("Running a simulator");
		
		double ret = -1;
		double fitness_collector = 0;
		int    runs              = 0;
		
		for ( int i = 0; i < this.destatic; ++i ) {
			++runs;
			fitness_collector += this._evaluate();
		}
		
		ret = ( fitness_collector / runs );
		this._cache_fitness = ret;
		return ret;
	}

	public double _evaluate(){
		double ret =-1;
		Simulator s = new Simulator(this.playerDNA);
		//Checks to ensure mating is working :-D 
		// System.out.println(this.playerDNA.toString());
		try {
			int score = s.blockingScoreRead();
			// System.out.println("Score: " + score);

			double fitness = (double)score / (double)20; // 20 is a great game.
			if ( fitness > 1 )
				fitness = 1;
			// System.out.println("OK. All good. Fitness of " + fitness);
			ret = fitness;
		} catch ( WTFException e ) {
			System.out.println("Failed to finish simulating, bad data.");
		}
		return ret;
	}
}